package edu.ua.bmr.android;

import java.util.ArrayList;
import java.util.HashMap;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.app.AlertDialog.Builder;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;

/**
 * This activity represents the user's current schedule for the currently
 * selected term. Here, the user can drop classes and navigate to the search
 * screen.
 * 
 * @author OEP
 * 
 */
public class SemesterActivity extends ListActivity implements Runnable {
	private static String TAG = "SemesterActivity";

	public static int REQUEST_SEARCH = 0;
	public static int REQUEST_VIEW = 1;

	/** Data for the Class ListView */
	private ArrayList<HashMap<String, String>> mData = new ArrayList<HashMap<String, String>>();

	/** Data for the Semester switch dialog */
	private ArrayList<HashMap<String, String>> mSemesters;

	/** Tells the user to wait */
	private Dialog mWaitDialog;

	/** The semester-switching dialog */
	private Dialog mSwitchDialog;
	private TextView mHeaderView;
	private TextView mFooterView;
	private Button mConfirmScheduleButton;
	private Button mAddClassButton;
	
	private OnClickListener mAddClassClickListener = new OnClickListener() {

		public void onClick(View v) {
			searchCatalog();
		}
	};
	
	private OnClickListener mConfirmScheduleClickListener = new OnClickListener() {

		public void onClick(View v) {
			mWaitDialog = BMR.showProgressDialog(SemesterActivity.this, R.string.please_wait,
					R.string.communicating_with_server);
			Thread t = new Thread( mConfirmSchedule );
			t.start();
		}
	};

	@Override
	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		Log.v( "SemesterActivity", "onCreate()" );
		this.setContentView(R.layout.act_semester);
		initUI();
		recache();
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		Log.v( "SemesterActivity", "onDestroy()" );

		// Ben: IMHO, no need to ever explicitly logout.
		// Session s = Session.getInstance();
		// s.logout();
	}

	/**
	 * Add the appropriate ListView headers and Listeners.
	 */
	private void initUI() {
		// Grab the listview that shows all the classes
		// ListView list = getListView();

		// Set the title to something cool!
		updateTitle();

		// Set the listener
		// list.setOnItemClickListener(mItemClicked);

		mConfirmScheduleButton = (Button)findViewById( R.id.btnConfirmSchedule );
		mConfirmScheduleButton.setOnClickListener( mConfirmScheduleClickListener );

		mAddClassButton = (Button)findViewById( R.id.btnAddClass );
		mAddClassButton.setOnClickListener( mAddClassClickListener );
		
		mHeaderView = new TextView(this);
		mHeaderView.setPadding(0, 0, 0, 0);
		mHeaderView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP);
		mHeaderView.setHeight(48);
		getListView().addHeaderView(mHeaderView, null, false);
		
		// Add the "Add class" footer
		mFooterView = new TextView(this);
		mFooterView.setText(R.string.switch_semester);
		mFooterView.setTextSize(24);
		mFooterView.setHeight(72);
		mFooterView.setTypeface(mFooterView.getTypeface(), Typeface.ITALIC);
		mFooterView.setPadding(10, 10, 10, 10);
		mFooterView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);		
		getListView().addFooterView(mFooterView);

//		updateUI();
		
	}

	/**
	 * Handles viewing the class when clicked or searching for classes if the
	 * user wants to add a new class.
	 */
	protected void onListItemClick(ListView l, View v, int position, long id) {

		if ( l.getHeaderViewsCount() > 0 && position == 0) {
			return;
		}
		
		// Did we click the trailer view?
		if (position == l.getAdapter().getCount() - 1) {
//			searchCatalog();
			showDialog( 0 );
			return;
		}

		// We clicked a class. We should pass this object
		// to ClassActivity.
		HashMap<String, String> map = (HashMap<String, String>) l
				.getItemAtPosition(position);

		// Construct the intent needed for viewing a class...
		Intent intent = BMR.getClassViewIntent(SemesterActivity.this, map);

		// We obviously are registered for this class.
		intent.putExtra(BMR.KEYWORD_REGISTERED, "1");

		// Start the next activity.
		startActivityForResult(intent, REQUEST_VIEW);
	}

	/** Thread for confirming schedule */
	private Runnable mConfirmSchedule = new Runnable() {
		public void run() {
			Session s = Session.getInstance();

			try {
				s.confirmSemester();

				// Prepare thy message!
				Message msg = new Message();

				// A success!
				msg.arg1 = 1;
				mConfirmScheduleHandler.sendMessage(msg);
			} catch (BMRException e) {
				// Oh poop. Make a message.
				Message msg = new Message();
				msg.arg1 = 0;
				msg.arg2 = e.getResourceId();

				mConfirmScheduleHandler.sendMessage(msg);
			}
		}
	};

	/**
	 * Handles messages passed the confirm schedule thread.
	 */
	private Handler mConfirmScheduleHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			mWaitDialog.dismiss();

			if (msg.arg1 == 1) {
				Toast.makeText(SemesterActivity.this, R.string.successful_confirm, Toast.LENGTH_SHORT ).show();
				updateUI();
				
			} else {
				// An exception was thrown. Build a dialog to tell the user.
				Builder builder = new AlertDialog.Builder(SemesterActivity.this);
				builder.setTitle(R.string.alert_error);
				builder.setMessage(msg.arg2);
				builder.setPositiveButton(R.string.button_ok, null);
				builder.show();
			}
		}
	};

	/** Thread for term-switching dialog */
	private Runnable mFetchSemesters = new Runnable() {
		public void run() {
			Session s = Session.getInstance();

			try {
				// See if we can stick some semesters in there..
				mSemesters = s.fetchSemesterList();

				// Prepare thy message!
				Message msg = new Message();

				// A success!
				msg.arg1 = 1;
				mSemesterListHandler.sendMessage(msg);
			} catch (BMRException e) {
				// Oh poop. Make a message.
				Message msg = new Message();
				msg.arg1 = 0;
				msg.arg2 = e.getResourceId();

				mSemesterListHandler.sendMessage(msg);
			}
		}
	};

	/**
	 * Handles messages passed by our login thread.
	 */
	private Handler mSemesterListHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			mWaitDialog.dismiss();

			if (msg.arg1 == 1) {
				// mSwitchDialog.show();
				SemesterActivity.this.showDialog(0);
			} else {
				// An exception was thrown. Build a dialog to tell the user.
				Builder builder = new AlertDialog.Builder(SemesterActivity.this);
				builder.setTitle(R.string.alert_error);
				builder.setMessage(msg.arg2);
				builder.setPositiveButton(R.string.button_ok, null);
				builder.show();
			}
		}
	};

	private OnItemClickListener mSemesterSelected = new OnItemClickListener() {

		public void onItemClick(AdapterView parent, View view, int position,
				long id) {
			Session s = Session.getInstance();
			ListView list = (ListView) mSwitchDialog
					.findViewById(R.id.semester_select_list);

			// We will receive a hashmap containing lots of data about the newly
			// selected semester
			HashMap<String, String> map = (HashMap<String, String>) list
					.getItemAtPosition(position);

			// Update the semester ID
			try {
				s.setSemesterId(map.get(BMR.TABLE_SEMESTER_ID));
			} catch (BMRException e) {
				// TODO: We probably should do something about this exception
				// here,
				// but at this point, the semester data MUST be cached so the
				// exception
				// won't be thrown.
				e.printStackTrace();
			}

			// Update the title
			updateTitle();

			mSwitchDialog.dismiss();
			SemesterActivity.this.recache();
		}
	};

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.menu_search_catalog:
			searchCatalog();
			return true;

		case R.id.menu_switch_semester:
			showTermSwitcher();
			return true;
		}
		return false;
	}

	private void showTermSwitcher() {
		if (mSemesters == null) {
			// We need to fetch the semesters this user can switch to. It might
			// take some time.
			mWaitDialog = BMR.showProgressDialog(this, R.string.please_wait,
					R.string.communicating_with_server);
			Thread t = new Thread(mFetchSemesters);
			t.start();
		} else {
			// Just go ahead and do it.
			// mSwitchDialog.show();
			showDialog(0);
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.menu_semester, menu);
		return true;
	}

	@Override
	public void onActivityResult(int request, int result, Intent intent) {
		if (result == ClassActivity.RESULT_DIRTY) {
			Log.i(TAG, "Data is dirty. Recaching.");
			recache();
		}
	}

//	@Override
//	public void onConfigurationChanged (Configuration newConfig) {
//		super.onConfigurationChanged(newConfig);
//		Log.i(TAG, "onConfigurationChanged()");		
//	}
	

	@Override
	protected void onPrepareDialog(int id, Dialog dialog) {
		super.onPrepareDialog(id, dialog);
	}

	@Override
	protected Dialog onCreateDialog(int id) {
		// Set up the semester switching dialog
		// Add its listeners
		// Set its layout
		mSwitchDialog = new Dialog(this);
		
		try {
			if ( mSemesters == null ) {
				Session s = Session.getInstance();
				mSemesters = s.fetchSemesterList();
			}
			mSwitchDialog.setTitle(R.string.select_a_semester);
			mSwitchDialog.setContentView(R.layout.dialog_semesters);
			ListView semesterList = (ListView) mSwitchDialog
					.findViewById(R.id.semester_select_list);
			semesterList.setOnItemClickListener(mSemesterSelected);
			
			semesterList.setAdapter(new SimpleAdapter(SemesterActivity.this, mSemesters,
					R.layout.singleitem_row, new String[] { "name" },
					new int[] { R.id.singleitem_text }));
	
		}
		catch ( Exception ex ) {
			Log.v( "SemesterActivity", ex.getMessage() );
			mSwitchDialog.setTitle("Failed to get semester list" );
		}
		

		return mSwitchDialog;
	}

	private void updateTitle() {
		Resources r = getResources();
		Session s = Session.getInstance();
		setTitle(r.getString(R.string.classes_for) + " " + s.getUsername() + ": " + s.getSemesterName());
	}

	/**
	 * Just an alias for starting the search classes activity.
	 */
	private void searchCatalog() {
		Intent i = new Intent(this, SearchActivity.class);
		startActivityForResult(i, REQUEST_SEARCH);
	}

	/**
	 * Handles messages passed by our login thread.
	 */
	private Handler mClassListHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			mWaitDialog.dismiss();

			if (msg.arg1 == 1) {
				updateUI();
			} else {
				// An exception was thrown. Build a dialog to tell the user.
				Builder builder = new AlertDialog.Builder(SemesterActivity.this);
				builder.setTitle(R.string.alert_error);
				builder.setMessage(msg.arg2);
				builder.setPositiveButton(R.string.button_ok, null);
				builder.show();
			}
		}
	};

	private void updateUI() {
		Session s = Session.getInstance();
		boolean hasData = mData != null && !mData.isEmpty();

		mAddClassButton.setVisibility( s.isAddable() ? View.VISIBLE : View.GONE );
		mConfirmScheduleButton.setVisibility( hasData && !s.isConfirmed() ? View.VISIBLE : View.GONE );
		
		if ( s.isAddable() ) {
			getListView().setFooterDividersEnabled(true);
		}
		else {
			getListView().setFooterDividersEnabled(false);
		}
		
		if ( !hasData ) {
			mHeaderView.setVisibility( View.VISIBLE );
			mHeaderView.setText( R.string.no_classes_registered );
			mHeaderView.setTextSize(16);
		}
		else if ( s.isConfirmed() ) {
			mHeaderView.setVisibility( View.VISIBLE );
			mHeaderView.setTextSize(16);
			mHeaderView.setText( R.string.already_confirmed );
		}
		else {
			mHeaderView.setVisibility( View.INVISIBLE );
			mHeaderView.setTextSize(1);
		}
		
		setListAdapter( new SimpleAdapter(
				SemesterActivity.this, mData, R.layout.classitem,
				BMR.CLASSLIST_FIELDS, BMR.CLASSLIST_VIEWS) );
	}

	public void run() {
		Session s = Session.getInstance();

		try {
			mData = s.fetchCurrentClasses();
			Message msg = new Message();
			msg.arg1 = 1;
			mClassListHandler.sendMessage(msg);
		} catch (BMRException e) {
			Message msg = new Message();
			msg.arg1 = 0;
			msg.arg2 = e.getResourceId();
			mClassListHandler.sendMessage(msg);
		}
	}

	private void recache() {
		Session s = Session.getInstance();
		
		if ( s.isCurrentClassListCached() ) {
			try {
				mData = s.fetchCurrentClasses();
				updateUI();
			}
			catch (BMRException e) {
				Message msg = new Message();
				msg.arg1 = 0;
				msg.arg2 = e.getResourceId();
				mClassListHandler.sendMessage(msg);
			}
		}
		else {
			// Hold yer horses please...
			mWaitDialog = BMR.showProgressDialog(this, R.string.please_wait,
					R.string.communicating_with_server);
	
			Thread t = new Thread(this);
			t.start();
		}
	}
}
